﻿// -----------------------------------------------------------------------
// <copyright file="ReadImage.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace ImageP
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class ReadImage
    {
        /// <summary>
        /// flag indicating whether in the P6 file there is a comment or not.
        /// </summary>
        public int Flag = 0;

        /// <summary>
        /// saves the comment written in the otherFormats.
        /// </summary>
        public string Comment;

        /// <summary>
        /// ImageHeight
        /// </summary>
        public int ImageHeight;

        ///<summary>image width ///</summary> 
        public int ImageWidth;

        ///<summary> image type of common formats whether P6,P3 ///</summary>
        public string ImgType;

        ///<summary> image location ///</summary>
        public string FilePath;

        ///<summary> object from struct to assign red, green, blue values ///</summary>
        public RGBcolor[,] Buffer;

        /// <summary>
        /// applying the quantization method by reducing bits per pixel.
        /// </summary>
        /// <param name="mask">mask</param>
        /// <param name="filepath">filepath</param>
        /// <returns>Bitmap</returns>
        public Bitmap Quantization(int mask, string filepath)
        {
            Bitmap m = new Bitmap(filepath);
            Bitmap m1 = new Bitmap(m.Width, m.Height);
            int pixelColor;
            int r1, r2, r3;
            int r, g, b;
            byte maskFinal = (255 << 5) & 0xFF;

            for (int i = 0; i < this.ImageHeight; i++)
            {
                for (int j = 0; j < this.ImageWidth; j++)
                {
                    pixelColor = m.GetPixel(j, i).ToArgb();
                    r = Color.FromArgb(pixelColor).R;
                    r1 = r & maskFinal;

                    g = Color.FromArgb(pixelColor).G;
                    r2 = g & maskFinal;

                    b = Color.FromArgb(pixelColor).B;
                    r3 = b & maskFinal;
                    m1.SetPixel(j, i, System.Drawing.Color.FromArgb(255, Convert.ToInt32(r1), Convert.ToInt32(r2), Convert.ToInt32(r3)));
                }
            }

            return m1;
        }

        /// <summary>
        /// detects other formats of images.
        /// </summary>
        /// <returns>Bitmap</returns>
        public Bitmap OpenOtherFormats()
        {
            Bitmap bm = new Bitmap(this.ImageWidth, this.ImageHeight);
            Color clr;

            for (int i = 0; i < this.ImageHeight; i++)
            {
                for (int j = 0; j < this.ImageWidth; j++)
                {
                    if (this.ImgType == "p3")
                    {
                        clr = Color.FromArgb(this.Buffer[i, j].Red, this.Buffer[i, j].Green, this.Buffer[i, j].Blue);
                        bm.SetPixel(j, i, System.Drawing.Color.FromArgb(255, this.Buffer[i, j].Red, this.Buffer[i, j].Green, this.Buffer[i, j].Blue));
                    }
                    else if (this.ImgType == "p6")
                    {
                        clr = Color.FromArgb(this.Buffer[i, j].Red, this.Buffer[i, j].Green, this.Buffer[i, j].Blue);
                        bm.SetPixel(j, i, System.Drawing.Color.FromArgb(255, this.Buffer[i, j].Red, this.Buffer[i, j].Green, this.Buffer[i, j].Blue));
                    }
                    else
                    {
                        clr = Color.FromArgb(Buffer[i, j].Red, Buffer[i, j].Green, Buffer[i, j].Blue);
                        bm.SetPixel(j, i, System.Drawing.Color.FromArgb(255, Buffer[i, j].Red, Buffer[i, j].Green, Buffer[i, j].Blue));
                    }
                }
            }

            return bm;
        }

        /// <summary>
        /// checking which one of the two other formats to load P3 ,P6
        /// </summary>
        public void LoadOtherFormats()
        {
            string line;
            StreamReader read = new StreamReader(this.FilePath);
            line = read.ReadLine();
            if (line == "P3" || line == "p3")
            {
                this.ImgType = "p3";
                this.LoadP3(read);
            }
            else if (line.Length >= 2)
            {
                string[] str = line.Split('#');
                if (line.Length > 2)
                {
                    this.Comment = str[1];
                    this.Flag = 1;
                }

                if (str[0] == "P6" || str[0] == "p6")
                {
                    this.ImgType = "p6";
                    this.LoadP6(read);
                }
            }
        }

        /// <summary>
        /// loads the PPM file of type P6
        /// </summary>
        /// <param name="file">file</param>
        public void LoadP6(StreamReader file)
        {
            string line;
            line = file.ReadLine();
            string[] size = line.Split(' ');
            this.ImageWidth = Convert.ToInt32(size[0]);
            this.ImageHeight = Convert.ToInt32(size[1]);
            line = file.ReadLine();

            int colorValue = Convert.ToInt32(line); //// maximum value of the color components for the pixels and this allows the format to describe more than single byte (0..255) color values.
            Bitmap bm = new Bitmap(Convert.ToInt32(this.ImageWidth), Convert.ToInt32(this.ImageHeight));
            this.Buffer = new RGBcolor[this.ImageHeight, this.ImageWidth];
            FileStream fileStream = new FileStream(this.FilePath, FileMode.Open, FileAccess.Read);

            for (int i = 0; i < this.ImageHeight; i++)
            {
                for (int j = 0; j < this.ImageWidth; j++)
                {
                    this.Buffer[i, j].Red = fileStream.ReadByte();

                    this.Buffer[i, j].Green = fileStream.ReadByte();

                    this.Buffer[i, j].Blue = fileStream.ReadByte();
                }
            }
        }

        /// <summary>
        /// loads the PPM file of type P3
        /// </summary>
        /// <param name="file">file</param>
        public void LoadP3(StreamReader file)
        {
            string line;
            int height = 0, width = 0;
            string[] color = null;
            while (height == 0 && width == 0)
            {
                line = file.ReadLine();
                this.Comment = line;
                if (line.StartsWith("#"))
                {
                    line = file.ReadLine();
                    color = line.Split(' ');
                    this.ImageWidth = Convert.ToInt32(color[0]);
                    width = this.ImageWidth;
                    this.ImageHeight = Convert.ToInt32(color[1]);
                    height = this.ImageHeight;
                    line = file.ReadLine();  ////255
                }
            }

            this.Buffer = new RGBcolor[height, width];
            line = file.ReadToEnd();
            char[] delimiters = new char[] { ' ', '\n', '\r' };
            color = line.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
            int numberOfElements = color.Length;
            int elements = -1;
            Bitmap bm = new Bitmap(Convert.ToInt32(width), Convert.ToInt32(height));
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    this.Buffer[i, j].Red = Convert.ToInt32(color[elements += 1]);
                    this.Buffer[i, j].Green = Convert.ToInt32(color[elements += 1]);
                    this.Buffer[i, j].Blue = Convert.ToInt32(color[elements += 1]);
                }
            }
        }

        /// <summary>
        /// loads common image foramts(extensions).
        /// </summary>
        public void LoadCommanFormats()
        {
            Bitmap commanBitmap = new Bitmap(this.FilePath);
            this.ImageHeight = commanBitmap.Height;
            this.ImageWidth = commanBitmap.Width;
            this.Buffer = new RGBcolor[this.ImageHeight, this.ImageWidth];
            for (int i = 0; i < this.ImageHeight; i++)
            {
                for (int j = 0; j < this.ImageWidth; j++)
                {
                    int x = commanBitmap.GetPixel(j, i).ToArgb();
                    Color my = Color.FromArgb(x);
                    this.Buffer[i, j].Red = commanBitmap.GetPixel(j, i).R;
                    this.Buffer[i, j].Green = commanBitmap.GetPixel(j, i).G;
                    this.Buffer[i, j].Blue = commanBitmap.GetPixel(j, i).B;
                }
            }
        }

        /// <summary>
        /// resize the image by using bilinear algorithm.
        /// </summary>
        /// <param name="newHeight">newHeight</param>
        /// <param name="newWidth">newWidth</param>
        /// <returns>Bitmap</returns>
        public Bitmap BilinearResizing(float newHeight, float newWidth)
        {
            float widthFactor = newWidth / this.ImageWidth;
            float heightFactor = newHeight / this.ImageHeight;
            int x1, x2, y1, y2;
            double fractionX, fractionY, one_minusX, one_minusY;
            double z1, z2;
            int finalR, finalG, finalB;
            int p1R, p2R, p3R, p4R, p1G, p2G, p3G, p4G, p1B, p2B, p3B, p4B;
            Bitmap bm = new Bitmap(Convert.ToInt32(newWidth), Convert.ToInt32(newHeight));
            double oldX, oldY;

            for (int i = 0; i < newHeight; i++)
            {
                for (int j = 0; j < newWidth; j++)
                {
                    oldX = j / widthFactor;
                    oldY = i / heightFactor;
                    x1 = Convert.ToInt32(Math.Floor(oldX));
                    x2 = x1 + 1;
                    y1 = Convert.ToInt32(Math.Floor(oldY));
                    y2 = y1 + 1;
                    if (x2 >= this.ImageWidth)
                    {
                        x2 = x1;
                    }

                    if (y2 >= this.ImageHeight)
                    {
                        y2 = y1;
                    }

                    fractionX = oldX - x1;
                    fractionY = oldY - y1;

                    ////if (xOld - x2 > fractionX)
                    ////    fractionX = xOld - x2;
                    ////if (yOld - y2 > fractionY)
                    ////    fractionY = yOld - y2;

                    one_minusX = 1 - fractionX;
                    one_minusY = 1 - fractionY;

                    p1R = this.Buffer[y1, x1].Red;
                    p2R = this.Buffer[y2, x1].Red;
                    p3R = this.Buffer[y1, x2].Red;
                    p4R = this.Buffer[y2, x2].Red;

                    p1G = this.Buffer[y1, x1].Green;
                    p2G = this.Buffer[y2, x1].Green;
                    p3G = this.Buffer[y1, x2].Green;
                    p4G = this.Buffer[y2, x2].Green;

                    p1B = this.Buffer[y1, x1].Blue;
                    p2B = this.Buffer[y2, x1].Blue;
                    p3B = this.Buffer[y1, x2].Blue;
                    p4B = this.Buffer[y2, x2].Blue;
                    z1 = (byte)((p1R * one_minusX) + (p2R * fractionX));
                    z2 = (byte)((p3R * one_minusX) + (p4R * fractionX));
                    finalR = (byte)((z1 * one_minusY) + (z2 * fractionY));
                    z1 = (byte)((p1G * one_minusX) + (p2G * fractionX));
                    z2 = (byte)((p3G * one_minusX) + (p4G * fractionX));
                    finalG = (byte)((z1 * one_minusY) + (z2 * fractionY));
                    z1 = (byte)((p1B * one_minusX) + (p2B * fractionX));
                    z2 = (byte)((p3B * one_minusX) + (p4B * fractionX));
                    finalB = (byte)((z1 * one_minusY) + (z2 * fractionY));
                    bm.SetPixel(j, i, System.Drawing.Color.FromArgb(255, finalR, finalG, finalB));
                }
            }

            return bm;
        }

        /// <summary>
        /// converts bitmap to buffer.
        /// </summary>
        /// <param name="img"> img </param>
        public void Bitmap_Buffer(Bitmap img)
        {
            this.ImageHeight = img.Height;
            this.ImageWidth = img.Width;
            this.Buffer = new RGBcolor[this.ImageHeight, this.ImageWidth];
            for (int i = 0; i < this.ImageHeight; i++)
            {
                for (int j = 0; j < this.ImageWidth; j++)
                {
                    int x = img.GetPixel(j, i).ToArgb();
                    Color my = Color.FromArgb(x);
                    this.Buffer[i, j].Red = img.GetPixel(j, i).R;
                    this.Buffer[i, j].Green = img.GetPixel(j, i).G;
                    this.Buffer[i, j].Blue = img.GetPixel(j, i).B;
                }
            }
        }
    }
}

/// <summary>
/// structure for each pixel represented in red, green, blue colors.
/// </summary>
public struct RGBcolor
{
    ///<summary> Red color in the picture ///</summary>
    public int Red;

    ///<summary> Green color in the picture ///</summary>
    public int Green;

    ///<summary> Blue color in the picture ///</summary>
    public int Blue;
}
